package com.xphu.nio.chatroom.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;

/**
 * 服务端
 * Created with IntelliJ IDEA.
 *
 * @author : xphu
 * @date : 2021-11-30 20:57
 */
public class NIOServer {
    public static void main(String[] args) throws IOException {
        // 创建ServerSocketChannel -> ServerSocket
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        // 绑定端口：6666，在服务端监听
        serverSocketChannel.socket().bind(new InetSocketAddress(6666));
        // 设置为非堵塞模式
        serverSocketChannel.configureBlocking(false);
        // 得到一个Selector
        Selector selector = Selector.open();
        // 把serverSocketChannel 注册到selector，事件为:OP_ACCEPT
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        // 循环等待客户端连接
        while (true) {
            // 这里我们等待1秒，如果没有事件发生，返回
            if (selector.select(1000) == 0) {
                System.out.println("服务器等待了1秒，无连接...");
                continue;
            }
            // 如果返回>0,则说明得到相关的selectionKeys集合
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            // 得到集合的迭代器便利事件
            Iterator<SelectionKey> keyIterator = selectionKeys.iterator();
            while (keyIterator.hasNext()) {
                // 获取到SelectionKey
                SelectionKey selectionKey = keyIterator.next();
                // 根据key 对应的通道发生的事件做相应的处理
                // 如果是OP_ACCEPT, 有新的客户端连接
                if (selectionKey.isAcceptable()) {
                    // 该客户端生成一个 SocketChannel
                    SocketChannel socketChannel = serverSocketChannel.accept();
                    // socketChannel设置为非堵塞的
                    socketChannel.configureBlocking(false);
                    System.out.println("客户端连接成功：" + socketChannel.hashCode());
                    // 将socketChannel 注册到selector,关注事件为 OP_READ,同时给socketChannel, 关联一个Buffer
                    socketChannel.register(selector, SelectionKey.OP_READ, ByteBuffer.allocate(1024));
                }
                // 发生 OP_READ
                if (selectionKey.isReadable()) {
                    // 通过key获取反向获取到对应的channel
                    SocketChannel channel = (SocketChannel) selectionKey.channel();
                    // 获取到该channel关联的buffer
                    ByteBuffer buffer = (ByteBuffer) selectionKey.attachment();
                    try {
                        channel.read(buffer);
                        System.out.println("form 客户端: " + new String(buffer.array(), "utf-8"));
                    } catch (Exception e) {
                        System.out.println("客户端强迫关闭了一个现有的连接。");
                        channel.close();
                    }
                }
                // 手动删除集合中移动当前的selectingKey, 防止重复操作
                keyIterator.remove();
            }
        }
    }
}
